#include "stdafx.h"
#include <boost/test/auto_unit_test.hpp>
#include "detail/bmock_arg_list.hpp"
#include "bmock_in_out_raw_mem.hpp"
#include "bmock_util.hpp"
#include <boost/iterator/transform_iterator.hpp>
#include "detail/bmock_test_control_tools.hpp"
#include <boost/array.hpp>

namespace bmock {

	static const control_tools_ptr          tl(new test_control_tools());
	static const int                        val1_0   = 123;
	static const int                        val1_1   = 125;
	static const int                        val1_2   = 567;
	static const int                        val1_3   = 369;
	static const int                        val1_4   = 789;
	static const char                       val2_0[] = "ABCDFG";
	static const char                       val2_1[] = "HIJKLM_";
	static const char                       val2_2[] = "NOPQRSTUV";
	static const size_t                     LEN2_2   = sizeof(val2_2);
	static const char                       val2_3[] = "123456789";
	static const size_t                     LEN2_3   = sizeof(val2_3);
	static const unsigned char		                 val3_0[]   = {0xAB,0xCD,0xEF,0x89};
	static const std::string                              s_val3_0   = "ABCDEF89";
	static const size_t                              LEN3_0     = sizeof(val3_0);
	static const unsigned char		                 val3_1[]   = {0x01,0x02,0x03,0x04,0x05,0x06};
	static const std::string                              s_val3_1   = "010203040506";
	static const size_t                              LEN3_1     = sizeof(val3_1);
	static const unsigned char	                     val3_2[]   = {0x11,0x12,0x13,0x14,0x15,0x16};
	static const std::string                              s_val3_2   = "111213141516";
	static const size_t                              LEN3_2     = sizeof(val3_2);
	static const unsigned char		                 val3_3[]   = {0x10,0x20,0x30,0x40,0x50,0x60,0x70};
	static const std::string                              s_val3_3   = "10203040506070";
	static const size_t                              LEN3_3     = sizeof(val3_3);
#define ARGS_COUNT   10
	static const boost::array<arg_val_str,ARGS_COUNT> expected = {
		arg_val_str(boost::lexical_cast<std::string>(val1_0),"")
		,arg_val_str(boost::lexical_cast<std::string>(val1_1),boost::lexical_cast<std::string>(val1_2))
		,arg_val_str(boost::lexical_cast<std::string>(val1_3),"")
		,arg_val_str(val2_0,"")
		,arg_val_str(val2_1,val2_2)
		,arg_val_str(s_val3_0,"")
		,arg_val_str(s_val3_1,s_val3_2)
		,arg_val_str("",boost::lexical_cast<std::string>(val1_4))
		,arg_val_str("",val2_3)
		,arg_val_str("",s_val3_3)
	};

	BOOST_AUTO_TEST_CASE(test_arg_list_get_value) {
		const in_out_raw_mem_descr<char>	rm2 = in_out_str(val2_1,val2_2);
		const in_out_raw_mem_descr<int>  rm1 = in_out_raw_mem(val1_1,val1_2);
		const in_out_raw_mem_descr<unsigned char> rm3(val3_1,LEN3_1,val3_2,LEN3_2);
		const in_out_raw_mem_descr<unsigned char> rm3_3 = out_raw_mem(val3_3,LEN3_3);
		__BMOCK_ARG_LIST(
			ARGS_COUNT
			,(IN(val1_0)
			,IN_OUT((int *)rm1)
			,IN(&val1_3)
			,IN(val2_0)
			,IN_OUT((char *)rm2)
			,RAW_MEM(IN,val3_0,LEN3_0)
			,RAW_MEM(IN_OUT,(unsigned char *)rm3,LEN3_1)
			,OUT((int *)&val1_4)
			,OUT((char *)val2_3)
			,RAW_MEM(OUT,(unsigned char *)rm3_3,LEN3_3))
			)

			arg_checker         ac(tl);
		std::vector<arg_val_str> vals;
		arg_list            al(args_,ARGS_COUNT);

		ac.set_location(location(__FILE__,__LINE__+1));
		BOOST_CHECK_NO_THROW(al.save(ac,back_inserter(vals)));
		BOOST_CHECK_EQUAL(
			size_t(ARGS_COUNT)
			,mismatch_at(
			expected.begin()
			,expected.end()
			,vals.begin()
			)
			);
	}

	BOOST_AUTO_TEST_CASE(test_arg_list_validate_OK) {
		int           res1 = val1_1;
		char          res2[sizeof(val2_1)];
		unsigned char res3[LEN3_1]; 
		int           res4;
		char          res5[LEN2_3];
		unsigned char res6[LEN3_3];

		strcpy(res2,val2_1);
		memcpy(res3,val3_1,LEN3_1);
		__BMOCK_ARG_LIST(
			ARGS_COUNT
			,(IN(val1_0)
			,IN_OUT(&res1)
			,IN(&val1_3)
			,IN(val2_0)
			,IN_OUT((char *)res2)
			,RAW_MEM(IN,val3_0,LEN3_0)
			,RAW_MEM(IN_OUT,(unsigned char *)res3,LEN3_1)
			,OUT(&res4)
			,OUT(res5)
			,RAW_MEM(OUT,res6,LEN3_3))
			)
			arg_checker ac(tl);
		arg_list    al(args_,ARGS_COUNT);

		ac.set_location(location(__FILE__,__LINE__+1));
		BOOST_CHECK(!al.args_differ(ac,expected.begin()));
	}

	BOOST_AUTO_TEST_CASE(test_arg_list_validate_Differ) {
		int           res1 = val1_1;
		char          res2[LEN2_2];
		unsigned char res3[LEN3_1+LEN3_2];
		int           res4;
		char          res5[LEN2_3];
		unsigned char res6[LEN3_3];

		strcpy(res2,val2_1);
		memcpy(res3,val3_1,LEN3_1);
		__BMOCK_ARG_LIST(
			ARGS_COUNT
			,(IN(val1_0+1)
			,IN_OUT(&res1)
			,IN(&val1_3)
			,IN(val2_0)
			,IN_OUT(res2)
			,RAW_MEM(IN,val3_0,LEN3_0)
			,RAW_MEM(IN_OUT,res3,LEN3_1)
			,OUT(&res4)
			,OUT(res5)
			,RAW_MEM(OUT,res6,LEN3_3))
			)
			arg_checker ac(tl);
		arg_list    al(args_,ARGS_COUNT);

		ac.set_location(location(__FILE__,__LINE__+1));
	}

	BOOST_AUTO_TEST_CASE(test_arg_list_update) {
		int           res1 = val1_1;
		char          res2[LEN2_2];
		unsigned char res3[LEN3_1+LEN3_2];
		int           res4;
		char          res5[LEN2_3];
		unsigned char res6[LEN3_3];


		strcpy(res2,val2_1);
		memcpy(res3,val3_1,LEN3_1);
		__BMOCK_ARG_LIST(
			ARGS_COUNT
			,(IN(val1_0)
			,IN_OUT(&res1)
			,IN(&val1_3)
			,IN(val2_0)
			,IN_OUT(res2)
			,RAW_MEM(IN,val3_0,LEN3_0)
			,RAW_MEM(IN_OUT,res3,LEN3_1)
			,OUT(&res4)
			,OUT(res5)
			,RAW_MEM(OUT,res6,LEN3_3))
			)
			arg_checker ac(tl);
		arg_list    al(args_,ARGS_COUNT);
		bool        result;

		BOOST_CHECK_NO_THROW(
			result = al.update_failed(ac,expected.begin());
		);
		BOOST_CHECK(!result);
		BOOST_CHECK_EQUAL(val1_2,res1);
		BOOST_CHECK_EQUAL(val2_2,res2);
		BOOST_CHECK_EQUAL(LEN3_2,mismatch_at(val3_2,val3_2+LEN3_2,res3));
		BOOST_CHECK_EQUAL(val1_4,res4);
		BOOST_CHECK_EQUAL(val2_3,res5);
		BOOST_CHECK_EQUAL(LEN3_3,mismatch_at(val3_3,val3_3+LEN3_3,res6));
	}

	BOOST_AUTO_TEST_CASE(test_arg_list_is_empty) {
		__BMOCK_ARG_LIST(0,())
			arg_list    al(args_,0);
		al.is_empty();
		BOOST_CHECK(al.is_empty());
	}
}
